%{
#include<stdio.h>
#include"arvsint.h"
#include"tabsimb.h"

/* Raiz */
No * raiz;

%}

%token ID
%token CLASS
%token PUBLIC
%token STATIC
%token VOID
%token MAIN
%token STRING
%token EXTENDS
%token RETURN
%token NEW
%token LENGTH
%token IF
%token WHILE
%token ELSE
%token TRUE
%token FALSE
%token THIS
%token SYSTEMOUTPRINTLN
%token MAIS
%token MENOS
%token VEZES
%token DIV
%token AND
%token OR
%token MENOR
%token MENORIG
%token MAIOR
%token MAIORIG
%token DIF
%token IGUAL
%token INT
%token BOOLEAN
%token INTVECTOR
%token XA
%token XF
%token CA
%token CF
%token PA
%token PF
%token LITERALINT
%token OPLN
%token IG
%token PT 
%token V
%token PV

%left OR AND
%left MENOR MAIOR
%left MENORIG MAIORIG
%left DIF IGUAL
%left MAIS MENOS
%left VEZES

%%

Goal: 			MainClass ClassDeclarationList 		{
									raiz = novoNoGoal(strdup("Teste"));
		  							ajustaOp1(raiz, (No *) $1);
   									ajustaOp2(raiz, (No *) $2);
								}
			;

MainClass:	 	CLASS Identifier XA
                                PUBLIC STATIC VOID MAIN PA STRING CA CF Identifier PF XA
                                   StatementList
                                                                                      XF
                                         XF {
						No * tmp;
						tmp = novoNoMainClasse();
						ajustaOp1(tmp, (No *) $2);	
					        ajustaOp2(tmp, (No *) $12);
						ajustaOp3(tmp, (No *) $15);
						$$ = tmp;
		    		            } 
			;

ClassDeclarationList:	ClassDeclaration ClassDeclarationList {
								No * tmp;
								tmp = novoNoDeclaracaoDeClasse();
								ajustaProximo(tmp, (No *) $2);
								$$ = tmp;
							      }
			|
			;

ClassDeclaration:	CLASS Identifier Extends XA VarDeclarationList MethodDeclarationList XF {
													No * tmp;
													tmp = novoNoDeclaracaoDeClasse();
													ajustaOp1(tmp, (No *) $2);
													ajustaOp2(tmp, (No *) $3);
													ajustaOp3(tmp, (No *) $5);
													ajustaOp4(tmp, (No *) $6);
													$$ = tmp;
												}
			;

Extends:		EXTENDS Identifier {
						No * tmp;
						tmp = novoNoExtende();
						ajustaOp1(tmp, $2);
						$$ = tmp;	
					   }
			|
			;

VarDeclarationList:	VarDeclaration VarDeclarationList {
							     No * tmp;
							     tmp = novoNoDeclaracaoDeVar();
							     ajustaProximo(tmp, (No *) $2);
							     $$ = tmp;	
							  }
			|
			;

VarDeclaration:		Type Identifier PV  {
						$$ = $2;
					    }
			;

MethodDeclarationList:	MethodDeclaration MethodDeclarationList {
							          No * tmp;
							          tmp = novoNoDeclaracaoDeMetodo();
							          ajustaProximo(tmp, (No *) $2);
							          $$ = tmp;	
							        }
			|
			;

MethodDeclaration:	PUBLIC Type Identifier PA TypeList PF XA StatementList RETURN Expression PV XF {
													 $$ = $2;	
												       }
			;

TypeList: 		Type Identifier RestTypeList
			|
			;

RestTypeList:		V Type Identifier RestTypeList
			|
			;

Type:		 	INT { $$ = novoNoTipo(); ajustaNome($$,"inteiro"); }
			|BOOLEAN { $$ = novoNoTipo(); ajustaNome($$,"boleano"); }
			|INTVECTOR { $$ = novoNoTipo(); ajustaNome($$,"vetor"); }
			|Identifier {$$ = $1;}
			;

StatementList:		Statement StatementList {
						   No * tmp;
					     	   tmp = novoNoChamada();
						   ajustaOp1(tmp, (No *) $1);
    						   ajustaProximo(tmp, (No *) $2);
					           $$ = tmp;
					        }
			|
			;


Statement:	 	XA StatementList XF { $$ = $1; }
			|IF PA Expression PF Statement ELSE Statement {
      									 No * tmp;
      									 tmp = novoNoSe();
      									 ajustaOp1(tmp, (No *) $3);
      									 ajustaProximo(tmp, (No *) $5);
									 $$ = tmp;
								      }
			|WHILE PA Expression PF Statement {
      								No *tmp;
      								tmp = novoNoEnquanto();
      								ajustaOp1(tmp, (No *) $3);
      								ajustaOp2(tmp, (No *) $5);
      							        $$ = tmp;
      							  }
			|SYSTEMOUTPRINTLN PA Expression PF PV {
      								No *tmp;
      								tmp = novoNoImprimir();
      								ajustaOp1(tmp, (No *) $3);
      								$$ = tmp;
      							      }
			|Identifier IG Expression PV {
   							No * tmp;
   							tmp = novoNoAtribuicao();
   							ajustaOp1(tmp, (No *) $1);
   							ajustaOp2(tmp, (No *) $3);
   							$$ = tmp;
						     }
			|Identifier CA Expression CF IG Expression PV {
   							                No * tmp;
   							                tmp = novoNoAtribuicao();
   							                ajustaOp1(tmp, (No *) $1);
   							                ajustaOp2(tmp, (No *) $3);
									ajustaOp3(tmp, (No *) $5);
   							                $$ = tmp;
						                      }
			|VarDeclaration {$$ = $1;}
			;

ExpressionList:		Expression RestExpressionList {
							No * tmp;
					     	        tmp = novoNoExpressao();	   							
							ajustaProximo(tmp, (No *) $2);
							$$ = tmp;
   						      }
			|
                        ;

RestExpressionList:	V Expression RestExpressionList {
   							No * tmp;
					     	        tmp = novoNoExpressao();  
							ajustaProximo(tmp, (No *) $3);
							$$ = tmp;
   						        }
			|
			;

Operator:		OR { $$ = novoNoOu(); }
			|AND { $$ = novoNoE(); }
       			|MENOR { $$ = novoNoMenor(); }	
			|MAIOR { $$ = novoNoMaior(); }
			|MENORIG { $$ = novoNoMenorOuIgual();	}
			|MAIORIG { $$ = novoNoMaiorOuIgual();	}
			|DIF { $$ = novoNoDiferente();	}
			|IGUAL { $$ = novoNoIgual(); }
			|MAIS { $$ = novoNoMais(); }
			|MENOS { $$ = novoNoMenos(); }
			|VEZES { $$ = novoNoMultiplicacao(); }
			|DIV { $$ = novoNoDivisao(); }
			;

Expression:	 	Expression Operator Expression {
      						         ajustaOp1((No *) $2, (No *)$1);
      						         ajustaOp2((No *) $2, (No *)$3);
      						         $$ = $2;
      					               }
			|Expression CA Expression CF {ajustaProximo((No *) $1, (No *) $3); }
			|Expression PT LENGTH {$$ = $1; }
	                |Expression PT Identifier PA ExpressionList PF {
   									ajustaOp1((No *) $1, (No *) $3);
									ajustaProximo((No *) $1, (No *) $5);   										$$ = $1;
   								       }
			|LITERALINT {
      				      No *tmp = novoNoInteiro();
      				      ajustaNome(tmp, $1);
      				      $$ = tmp;
      			            }
			|TRUE
			|FALSE
			|Identifier { $$ = $1; }
			|THIS
			|NEW INT CA Expression CF { $$ = $4; }
			|NEW Identifier PA PF {$$ = $2;}
			|OPLN Expression {	
   	   					No *tmp = novoNoNegacao();
   						ajustaProximo(tmp, $2);
   						$$ = tmp;
				 	 }
			|PA Expression PF { $$ = $1; }
             		;


Identifier:	 	ID 		{
      						No *tmp = novoNoId();
      						ajustaNome(tmp, $1);
      						$$ = tmp;
      					}
			;

%%


#include "lex.yy.c"

int main() {
	debug = 0;
	raiz = NULL;
	yyparse();
	mostraArvore(raiz, 0);
	destroiArvore(raiz);
}

yyerror(char* s) {
  printf("\nErro sintatico na linha %d, caracter invalido: %s\n, %s\n", 
			yylineno, yytext, s);
      
  exit(1);
}
